package com.springboot.ball.consumer;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.springboot.ball.consumer.games.Game;
import com.springboot.ball.consumer.games.Player;
import com.springboot.ball.consumer.utils.JwtAuthentication;
import com.springboot.ball.mapper.ChatMessageMapper;
import com.springboot.ball.mapper.UserMapper;
import com.springboot.ball.pojo.ChatMessage;
import com.springboot.ball.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;

import java.io.IOException;
import java.time.LocalDateTime;

import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

@Slf4j
@Component
@ServerEndpoint("/websocket/{token}")  // 注意不要以'/'结尾
public class WebSocketServer {

    final public static ConcurrentHashMap<Integer, WebSocketServer> users = new ConcurrentHashMap<>();
    private User user;
    private Session session = null;
    final private static CopyOnWriteArraySet<User> matchpool = new CopyOnWriteArraySet<>();
    private static UserMapper userMapper;
    private static ChatMessageMapper chatMessageMapper;

    private Game game=null;


    @Autowired
    public void setUserMapper(UserMapper userMapper) {
        WebSocketServer.userMapper = userMapper;
    }

    @Autowired
    public void setChatMessageMapper(ChatMessageMapper chatMessageMapper) {
        WebSocketServer.chatMessageMapper = chatMessageMapper;
    }

    private void saveMessage(JSONObject data) {
        ChatMessage message = new ChatMessage();
        message.setFromUserId(this.user.getId());
        message.setToUserId(data.getInteger("to"));
        message.setContent(data.getString("content"));
        message.setCreateTime(LocalDateTime.now());
        log.info("保存聊天内容: {}", message);
        chatMessageMapper.insert(message);//保存聊天内容到数据库
    }

    private void broadcastOnlineUsers() {
        JSONObject message = new JSONObject();
        message.put("event", "online-users");
        JSONArray usersList = new JSONArray();
        for (WebSocketServer server : users.values()) {
            if (server.user != null) {
                User u = server.user;
                JSONObject userJson = new JSONObject();
                userJson.put("id", u.getId());
                userJson.put("username", u.getUsername());
                userJson.put("photo", u.getPhoto());
                usersList.add(userJson);
            }
        }
        message.put("users", usersList);
        String msg = message.toJSONString();
        
        // 为了避免并发问题，创建一个用户列表的副本然后遍历
        java.util.ArrayList<WebSocketServer> serversCopy = new java.util.ArrayList<>(users.values());
        for (WebSocketServer server : serversCopy) {
            try {
                if (server != null && server.session != null && server.session.isOpen()) {
                    server.sendMessage(msg);
                }
            } catch (Exception e) {
                log.error("广播在线用户时出错: {}", e.getMessage());
            }
        }
    }

    // 在类内添加消息处理方法
    private void handlePrivateMessage(JSONObject data) {
        int toUserId = data.getInteger("to");
        String content = data.getString("content");

        WebSocketServer target = users.get(toUserId);
        if (target != null && target.session.isOpen()) {
            // 发送消息通知
            JSONObject notification = new JSONObject();
            notification.put("event", "new-message");
            notification.put("from", this.user.getId());
            notification.put("fromName", this.user.getUsername());
            notification.put("content", content);
            notification.put("timestamp", System.currentTimeMillis());
            target.sendMessage(notification.toJSONString());

            JSONObject message = new JSONObject();
            message.put("event", "private-message");
            message.put("from", this.user.getId());
            message.put("fromName", this.user.getUsername());
            message.put("content", content);
            message.put("timestamp", System.currentTimeMillis());
            // 发送消息到发送者
            target.sendMessage(message.toJSONString());
        }
    }
    private void sendHistoryMessage(Integer from, Integer to) {
        List<ChatMessage> messages = chatMessageMapper.selectHistory(from, to);
        JSONObject event = new JSONObject();
        event.put("event", "history-message");
        event.put("messages", messages);
        sendMessage(event.toJSONString());
    }

    // 发送好友请求通知
    public static void sendFriendRequest(Integer fromUserId, Integer toUserId) {
        WebSocketServer target = users.get(toUserId);
        if (target != null) {
            User fromUser = userMapper.selectById(fromUserId);
            JSONObject message = new JSONObject();
            message.put("event", "friend-request");

            message.put("fromUserId", fromUserId);
            message.put("fromUsername", fromUser.getUsername());
            message.put("fromUserPhoto", fromUser.getPhoto());
            message.put("createTime", LocalDateTime.now().toString());
            target.sendMessage(message.toJSONString());
        }
    }
    @OnOpen
    public void onOpen(Session session, @PathParam("token") String token) throws IOException {
        //  建立连接时自动调用
        this.session = session;
        log.info("connect!");
        int userId = JwtAuthentication.getUserId(token);
        this.user = userMapper.selectById(userId);
        if (this.user != null) {
            users.put(userId, this);
            broadcastOnlineUsers(); // 新增：广播在线用户列表
        } else {
            this.session.close();
        }
        System.out.println(users);
    }

    @OnClose
    public void onClose() {
        // 关闭链接时自动调用
        log.info("close!");
        if (user != null) {
            users.remove(this.user.getId());
            matchpool.remove(this.user);
            broadcastOnlineUsers(); // 新增：广播在线用户列表
        }
    }

    private void startMatching() {
        System.out.println("startMatching");
        matchpool.add(this.user);
        //现在还没有实现微服务，暂时先实现一个傻瓜式的匹配
        while (matchpool.size() >= 3) {
            Iterator<User> iterator = matchpool.iterator();
            User user1 = iterator.next();
            User user2 = iterator.next();
            User user3 = iterator.next();

            // 从匹配池移除三个用户
            matchpool.remove(user1);
            matchpool.remove(user2);
            matchpool.remove(user3);

            Game game = new Game(user1.getId(), user2.getId(), user3.getId());
            game.createMap();

            users.get(user1.getId()).game = game;
            users.get(user2.getId()).game = game;
            users.get(user3.getId()).game = game;// 将游戏对象设置为用户对应的游戏对象
            game.start();

            JSONObject respGame = new JSONObject();
            respGame.put("a_id",game.getPlayerA().getId());
            respGame.put("b_id",game.getPlayerB().getId());
            respGame.put("c_id",game.getPlayerC().getId());
            respGame.put("a_x", game.getPlayerA().getX());
            respGame.put("b_x", game.getPlayerB().getX());
            respGame.put("c_x", game.getPlayerC().getX());
            respGame.put("a_y", game.getPlayerA().getY());
            respGame.put("b_y", game.getPlayerB().getY());
            respGame.put("c_y", game.getPlayerC().getY());
            respGame.put("a_radius", game.getPlayerA().getRadius());
            respGame.put("b_radius", game.getPlayerB().getRadius());
            respGame.put("c_radius", game.getPlayerC().getRadius());
            respGame.put("a_speed", game.getPlayerA().getSpeed());
            respGame.put("b_speed", game.getPlayerB().getSpeed());
            respGame.put("c_speed", game.getPlayerC().getSpeed());
            respGame.put("map", game.getG());

            // 给user1发送两个对手的信息
            JSONObject resp1 = new JSONObject();
            resp1.put("event", "start-matching");
            resp1.put("opponent1_id", user2.getId());
            resp1.put("opponent1_username", user2.getUsername());
            resp1.put("opponent1_photo", user2.getPhoto());
            resp1.put("opponent2_id", user3.getId());
            resp1.put("opponent2_username", user3.getUsername());
            resp1.put("opponent2_photo", user3.getPhoto());
            resp1.put("game", respGame);
            users.get(user1.getId()).sendMessage(resp1.toJSONString());

            // 给user2发送两个对手的信息
            JSONObject resp2 = new JSONObject();
            resp2.put("event", "start-matching");
            resp2.put("opponent1_id", user1.getId());
            resp2.put("opponent1_username", user1.getUsername());
            resp2.put("opponent1_photo", user1.getPhoto());
            resp2.put("opponent2_id", user3.getId());
            resp2.put("opponent2_username", user3.getUsername());
            resp2.put("opponent2_photo", user3.getPhoto());
            resp2.put("game", respGame);
            users.get(user2.getId()).sendMessage(resp2.toJSONString());

            // 给user3发送两个对手的信息
            JSONObject resp3 = new JSONObject();
            resp3.put("event", "start-matching");
            resp3.put("opponent1_id", user1.getId());
            resp3.put("opponent1_username", user1.getUsername());
            resp3.put("opponent1_photo", user1.getPhoto());
            resp3.put("opponent2_id", user2.getId());
            resp3.put("opponent2_username", user2.getUsername());
            resp3.put("opponent2_photo", user2.getPhoto());
            resp3.put("game", respGame);
            users.get(user3.getId()).sendMessage(resp3.toJSONString());
        }
    }

    private void stopMatching() {
        System.out.println("stopMatching");
        matchpool.remove(this.user);
    }

    private void move(JSONObject data) {
        if (game != null) {
            int x = data.getInteger("x");
            int y = data.getInteger("y");
            
            // 获取玩家对象
            Player playerObj = null;
            
            // 根据玩家ID判断是哪个玩家
            if (game.getPlayerA().getId().equals(user.getId())) {
                playerObj = game.getPlayerA();
            } else if (game.getPlayerB().getId().equals(user.getId())) {
                playerObj = game.getPlayerB();
            } else if (game.getPlayerC().getId().equals(user.getId())) {
                playerObj = game.getPlayerC();
            }
            
            // 检查玩家是否存在且存活
            if (playerObj != null && playerObj.isAlive()) {
                // 创建包含玩家ID的移动事件，便于前端识别哪个玩家移动
                JSONObject moveEvent = new JSONObject();
                moveEvent.put("event", "move");
                moveEvent.put("player_id", user.getId());
                moveEvent.put("x", x);
                moveEvent.put("y", y);
                
                // 广播移动事件给所有玩家，这样所有玩家都能看到其他玩家的移动
                game.sendAllMessage(moveEvent.toJSONString());
                
                // 设置玩家下一步的移动
                if (game.getPlayerA().getId().equals(user.getId())) {
                    game.setNextStepA(x, y);
                } else if (game.getPlayerB().getId().equals(user.getId())) {
                    game.setNextStepB(x, y);
                } else if (game.getPlayerC().getId().equals(user.getId())) {
                    game.setNextStepC(x, y);
                }
            } else {
                // 玩家已死亡，不处理移动请求
                System.out.println("玩家已死亡，无法移动: " + user.getId());
            }
        }
    }

    // 添加技能处理方法
    private void handleSkill(JSONObject data) {
        if (game != null) {
            String skillType = data.getString("type");
            int targetX = data.getInteger("x");
            int targetY = data.getInteger("y");
            
            // 获取玩家对象
            Player playerObj = null;
            
            // 根据用户ID查找对应玩家
            if (game.getPlayerA().getId().equals(user.getId())) {
                playerObj = game.getPlayerA();
            } else if (game.getPlayerB().getId().equals(user.getId())) {
                playerObj = game.getPlayerB();
            } else if (game.getPlayerC().getId().equals(user.getId())) {
                playerObj = game.getPlayerC();
            }
            
            // 检查玩家是否存在且存活才允许使用技能
            if (playerObj != null && playerObj.isAlive()) {
                game.playerUseSkill(playerObj, skillType, targetX, targetY);
            } else {
                // 玩家已死亡，不处理技能请求
                System.out.println("玩家已死亡，无法使用技能: " + user.getId());
            }
        }
    }

    // 处理玩家死亡
    private void handlePlayerDeath(JSONObject data) {
        if (game != null) {
            Integer playerId = data.getInteger("player_id");
            String playerIdentifier = null;
            
            // 根据玩家ID判断是哪个玩家
            if (game.getPlayerA().getId().equals(playerId)) {
                playerIdentifier = "A";
                game.playerDeath("A");
            } else if (game.getPlayerB().getId().equals(playerId)) {
                playerIdentifier = "B";
                game.playerDeath("B");
            } else if (game.getPlayerC().getId().equals(playerId)) {
                playerIdentifier = "C";
                game.playerDeath("C");
            }
            
            // 广播死亡消息给所有客户端，确保所有客户端都能正确移除死亡玩家
            if (playerIdentifier != null) {
                JSONObject deathEvent = new JSONObject();
                deathEvent.put("event", "player_death");
                deathEvent.put("player_id", playerId);
                deathEvent.put("identifier", playerIdentifier);
                game.sendAllMessage(deathEvent.toJSONString());
                
                // 同步当前健康状态，确保所有客户端显示一致
                game.checkHealthSync();
            }
        }
    }

    // 处理玩家受伤事件，更新健康值
    private void handleDamage(JSONObject data) {
        if (game != null) {
            Integer playerId = data.getInteger("player_id");
            Double health = data.getDouble("health");
            
            // 根据用户ID确认是否是有效的伤害请求
            if (!user.getId().equals(playerId)) {
                // 如果请求的playerId与当前用户不匹配，拒绝处理
                return;
            }
            
            // 不需要再次发送伤害事件，只更新玩家状态
            // 这是从玩家端确认的伤害信息，只需要更新服务器状态
            
            // 确认当前血量
            double currentHealth = 0;
            if (game.getPlayerA().getId().equals(playerId)) {
                currentHealth = game.getPlayerA().getHealth();
            } else if (game.getPlayerB().getId().equals(playerId)) {
                currentHealth = game.getPlayerB().getHealth();
            } else if (game.getPlayerC().getId().equals(playerId)) {
                currentHealth = game.getPlayerC().getHealth();
            }
            
            // 防止重复伤害：确保新血量低于当前血量，且差值不超过预期
            if (health >= currentHealth || currentHealth - health > 30) {
                return; // 拒绝无效的血量变化
            }
            
            // 更新玩家生命值到游戏对象
            if (game.getPlayerA().getId().equals(playerId)) {
                game.getPlayerA().setHealth(health);
            } else if (game.getPlayerB().getId().equals(playerId)) {
                game.getPlayerB().setHealth(health);
            } else if (game.getPlayerC().getId().equals(playerId)) {
                game.getPlayerC().setHealth(health);
            }
            
            // 发送伤害信息给所有客户端 - 仅广播一次
            JSONObject damageEvent = new JSONObject();
            damageEvent.put("event", "damage");
            damageEvent.put("player_id", playerId);
            damageEvent.put("health", health);
            
            // 广播伤害事件
            game.sendAllMessage(damageEvent.toJSONString());
            
            // 检查玩家是否死亡
            if (health <= 0) {
                if (game.getPlayerA().getId().equals(playerId)) {
                    game.playerDeath("A");
                } else if (game.getPlayerB().getId().equals(playerId)) {
                    game.playerDeath("B");
                } else if (game.getPlayerC().getId().equals(playerId)) {
                    game.playerDeath("C");
                }
            }
        }
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        // Server从Client接收消息时触发，路由消息
        //log.info("receive message");
        JSONObject data = JSONObject.parseObject(message);
        String event = data.getString("event");

        switch (event) {
            case "start-matching":
                startMatching();
                break;
            case "stop-matching":
                stopMatching();
                break;
            case "private-message":  // 新增处理私聊消息
                saveMessage(data);  // 新增存储调用
                handlePrivateMessage(data);
                break;
            case "friend-request":
                sendFriendRequest(user.getId(), data.getInteger("toUserId"));
                break;
            case "friend-update":
                sendFriendUpdate(user.getId(), data.getInteger("toUserId"), data.getString("status"));
                break;
            case "get-history": // 新增历史消息请求
                sendHistoryMessage(
                        data.getInteger("from"),
                        data.getInteger("to")
                );
                break;
            case "move":
                move(data);
                break;
            case "skill":
                handleSkill(data);
                break;
            case "damage": 
                handleDamage(data);
                break;
            case "player_death":
                handlePlayerDeath(data);
                break;
        }
    }


    // 新增通知方法
    public static void sendFriendUpdate(Integer user1, Integer user2, String status) {
        notifyUser(user1, status);
        notifyUser(user2, status);
    }

    private static void notifyUser(Integer fromUserId, String status) {
        WebSocketServer target = users.get(fromUserId);
        if (target != null) {
            JSONObject msg = new JSONObject();
            msg.put("event", "friend-update");
            msg.put("status", status);
            target.sendMessage(msg.toJSONString());
        }
    }




    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    public void sendMessage(String message) {
        if (this.session == null) {
            log.warn("尝试向未连接的会话发送消息");
            return;
        }
        
        synchronized (this.session) {
            try {
                if (this.session.isOpen()) {
                    this.session.getBasicRemote().sendText(message);
                } else {
                    log.warn("尝试向已关闭的会话发送消息");
                }
            } catch (IOException e) {
                log.error("发送消息出错: {}", e.getMessage());
            }
        }
    }

}
